package com.gopay.common.log.logxnew.dao.impl;

import com.gopay.common.base.dao.impl.BaseDAOImpl;
import com.gopay.common.domain.log.OperLogAssistDtl;
import com.gopay.common.domain.log.OperLogBankRouteDtl;
import com.gopay.common.domain.log.OperLogDtl;
import com.gopay.common.log.logxnew.dao.OperLogAssistDtlDAO;
import com.gopay.common.log.logxnew.dao.OperLogBankRouteDtlDAO;
import com.gopay.common.log.logxnew.dao.OperLogDtlDAO;
import com.gopay.common.log.logxnew.dao.OperLogDtlManager;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 操作日志记录表Manager实现类
 *
 * @OperLogDtlManagerImpl.java
 * @author zhoutong
 * @2017-6-15 上午11:09:49 www.gopay.com.cn Inc.All rights reserved.
 */
@Service("operLogDtlManager")
public class OperLogDtlManagerImpl extends BaseDAOImpl implements OperLogDtlManager {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    static String replaceDefValuePattern = "\\$\\{(.*?)}";

    @Resource(name = "operLogDtlDAO")
    private OperLogDtlDAO operLogDtlDAO;

    @Resource(name = "operLogAssistDtlDAO")
    private OperLogAssistDtlDAO operLogAssistDtlDAO;

    @Resource(name = "operLogBankRouteDtlDAO")
    private OperLogBankRouteDtlDAO operLogBankRouteDtlDAO;

    private static Map<String,String> operDescMap = null;

    private static final byte[] LOCK = new byte[0];

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class })
    public void saveLog(OperLogDtl log){
        //查表设置操作详情
        setOperDesc(log);

        OperLogDtl operLogDtl = operLogDtlDAO.save(log);
        if(log.getAssistDtl() != null) {
            OperLogAssistDtl assistDtl = log.getAssistDtl();
            assistDtl.setLogId(operLogDtl.getLogId());
            operLogAssistDtlDAO.save(assistDtl);
        }
        if(log.getBankRouteDtl() != null) {
            OperLogBankRouteDtl bankRouteDtl = log.getBankRouteDtl();
            bankRouteDtl.setLogId(operLogDtl.getLogId());
            operLogBankRouteDtlDAO.save(bankRouteDtl);
        }
    }

    @Override
    public OperLogDtl findOperLogDtlByParams(Map<String, String> params) {
        return operLogDtlDAO.findOperLogDtlByParams(params);
    }

    @Override
    public void replacePwdCtrlTempId(Long tempId, Long pwdCtrlInfoId) {
        String hql = "from OperLogDtl where pwdCtrlAttrInfoId = :pwdCtrlAttrInfoId ";
        Map<String, Object> param = new HashMap<>(2);
        param.put("pwdCtrlAttrInfoId", tempId);
        List<OperLogDtl> logs = operLogDtlDAO.findByHql(hql, param);
        if(!logs.isEmpty()){
            OperLogDtl log = logs.get(0);
            log.setPwdCtrlAttrInfoId(pwdCtrlInfoId);
            update(log);
        }
    }

    private void setOperDesc(OperLogDtl log) {
        operDescMap = getOperDescMap();
        if(operDescMap != null && !operDescMap.isEmpty()) {
            StringBuilder key = new StringBuilder();
            key.append(log.getPlatform()).append("_").append(log.getCategory()).append("_").append(log.getModules()).append("_").append(log.getOperTypeCd());
            String operDescDef = operDescMap.get(key.toString());
            if(operDescDef != null && !"".equals(operDescDef)) {
                JSONObject jsonObject = JSONObject.fromObject(log);
                String operDesc = replaceDefValue(operDescDef,jsonObject);
                log.setOperDesc(operDesc);
            } else {
                logger.error("ERROR key:"+key.toString()+",value:"+operDescDef);
            }
        }
    }

    private static String replaceDefValue(String operDescDef, JSONObject jsonObject) {
        Pattern p = Pattern.compile(replaceDefValuePattern);
        Matcher m = p.matcher(operDescDef);
        while(m.find()){
            String key  = m.group(1);
            String $key = m.group();
            String value = "";
            if(key.contains(".")) {
                String[] temp = key.split("\\.");
                String cObj = temp[0];
                String cField = temp[1];
                //JSONObject判断空
                if(jsonObject.get(cObj) != null &&
                        !(jsonObject.get(cObj) instanceof JSONNull)) {
                    JSONObject cJsonObject = (JSONObject)(jsonObject.get(cObj));
                    if(cJsonObject != null && cJsonObject.containsKey(cField)) {
                        value = (String)cJsonObject.get(cField);
                    }
                }
            } else {
                value = (String) jsonObject.get(key);
            }
            operDescDef = operDescDef.replace($key,value);
        }
        return operDescDef;
    }

    private Map<String,String> getOperDescMap() {
        if(operDescMap == null) {
            synchronized (LOCK) {
                if(operDescMap == null) {
                    operDescMap = buildOperDescMap();
                }
            }
        }
        return operDescMap;
    }

    private Map<String,String> buildOperDescMap() {
        String sql = "SELECT t.platform,t.category,t.modules,t.oper_type_cd,t.oper_desc_def FROM  DIC_LOG_DESC_TEMP t";
        List<Object[]> list = this.findBySql(sql);
        Map<String,String> map = new HashMap<>();
        if(list != null && !list.isEmpty()) {
            for(int i = 0;i < list.size();i++) {
                Object[] obj = list.get(i);
                String platform = (String) obj[0];
                String category = (String) obj[1];
                String modules = (String) obj[2];
                String operTypeCd = (String) obj[3];
                String operDescDef = (String) obj[4];
                StringBuilder key = new StringBuilder();
                key.append(platform).append("_").append(category).append("_").append(modules).append("_").append(operTypeCd);
                map.put(key.toString(),operDescDef);
            }
        }
        return map;
    }

}
